package io.gitee.pkmer.designpattern.strategy;

import io.gitee.pkmer.base.ApplicationContextHolder;
import io.gitee.pkmer.base.init.ApplicationInitializingEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 策略选择
 *
 * @author 胖卡
 * @version 1.0.0
 * @date 2024/6/20
 */
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Slf4j
public abstract class StrategyChoose<T,Key, Value extends AbstractExecuteStrategy<? extends T, ?>> implements ApplicationListener<ApplicationInitializingEvent> {
    private final Map<Key, Value> abstractExecuteStrategyMap = new HashMap<>();

    protected Value choose(Key key) {
        return Optional.ofNullable(abstractExecuteStrategyMap.get(key))
                .orElseThrow(() -> new RuntimeException(String.format("[%s] 策略未定义", key.getClass().getSimpleName())));
    }



    @Override
    public void onApplicationEvent(ApplicationInitializingEvent event) {
        log.info("监听到ApplicationInitializingEvent事件,准备添加配置CommandHandler");
        Map<String, AbstractExecuteStrategy> beansOfType = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);
        beansOfType.forEach((beanName, bean) -> {

            Key keyType = getKeyType(bean);
            AbstractExecuteStrategy<?, ?> stragegy = abstractExecuteStrategyMap.get(keyType);
            if (stragegy != null) {
                throw new RuntimeException(String.format("[%s] Duplicate execution policy", bean));
            } else {
                abstractExecuteStrategyMap.put(keyType, (Value)bean);
                if (isClassType(keyType)) {
                    log.info("添加{} -> {} success", ((Class<?>) keyType).getSimpleName(), bean.getClass().getSimpleName());
                } else {
                    log.info("添加{} -> {} success", keyType.getClass().getSimpleName(), bean.getClass().getSimpleName());
                }
            }
        });
    }


    /**
     * 获取策略Bean处理Key的类型
     *
     * @return Key
     */
    private Key getKeyType(AbstractExecuteStrategy strategy) {
        ParameterizedType genericParameterInterface = (ParameterizedType) strategy.getClass().getGenericInterfaces()[0];
        Type actualTypeArgument = genericParameterInterface.getActualTypeArguments()[0];
        return (Key) actualTypeArgument;
    }

    /**
     * 判断是否是Class类型
     *
     * @param obj 要判断的对象
     * @return true 是Class类型 false 不是Class类型
     */
    private boolean isClassType(Object obj) {
        return obj instanceof Class;
    }

}
